
/*
    虚拟机模块：
    一个虚拟机包含交换机，队列,交换机与队列之间存在绑定关系，消息的载体是队列
    所以虚拟机模块是对交换机模块，队列模块，绑定关系模块，消息模块的整合
*/
#ifndef __M_HOST_H__
#define __M_HOST_H__
#include "mq_exchange.hpp"
#include "mq_queue.hpp"
#include "mq_binding.hpp"
#include "mq_message.hpp"

namespace xgmq
{
    class VirtualHost
    {
    public:
        using ptr=std::shared_ptr<VirtualHost>;
        VirtualHost(const std::string& hostname,std::string basedir, const std::string &dbfile)
            : _exchange(std::make_shared<ExchangeManagger>(dbfile)),
              _queue(std::make_shared<MsqQueueManagger>(dbfile)),
              _binding(std::make_shared<BindingManager>(dbfile)),
              _message(std::make_shared<MessageManager>(basedir)),
              _hostname(hostname)
        {
            // 获取到所有的队列名称，通过队列名称恢复历史数据
            MsgQueueMap mp = _queue->allQueues();
            for (auto &q : mp)
            {
                _message->initQueueMessage(q.first);
            }
        }

        // 声明/创建一个交换机
        void declareExchange(const std::string &ename,
                             ExchangeType etype,
                             bool edurable,
                             bool edelete,
                             const google::protobuf::Map<std::string,std::string>& eargs)
        {
            _exchange->declareExchange(ename, etype, edurable, edelete, eargs);
        }
        //获取交换机
        ExchangePtr getExchange(const std::string& name)
        {
            return _exchange->getExchange(name);
        }
        // 删除一个交换机
        void deleteExchange(const std::string &ename)
        {
            // 删除交换机之前，也要将其所有的绑定关系删除掉
            _binding->removeExchangeBinding(ename);
            _exchange->deleteExchange(ename);
        }

        // 声明/创建一个队列
        bool declareQueue(const std::string &qname,
                          bool qdurable,
                          bool qexclusive,
                          bool qauto_delete,
                          const google::protobuf::Map<std::string,std::string>& qargs)
        {
            // 初始化队列消息，从文件中恢复到内存中
            _message->initQueueMessage(qname);
            return _queue->declareQueue(qname, qdurable, qexclusive, qauto_delete, qargs);
        }
        // 删除一个队列
        void deleteQueue(const std::string &qname)
        {
            // 删除队列时，要删除队列的绑定信息和队列消息
            _binding->removeQueueBinding(qname);
            _message->destoryQueueMessage(qname);
            _queue->deleteQueue(qname);
        }

        // 设置一个绑定关系
        bool bind(const std::string &ename, const std::string &qname, const std::string &key)
        {
            // 交换机必须得存在
            ExchangePtr exp = _exchange->getExchange(ename);
            if (exp.get() == nullptr)
            {
                DLOG("设置绑定关系失败,交换机%s不存在\n", ename.c_str());
                return false;
            }
            // 队列必须得存在
            MsgQueue::ptr mq = _queue->getQueue(qname);
            if (mq.get() == nullptr)
            {
                DLOG("设置绑定关系失败,队列%s不存在\n", qname.c_str());
                return false;
            }
            bool durable = exp->durable && mq->durable;
            return _binding->bind(ename, qname, key, durable);
        }
        // 解除一个绑定关系
        void unbind(const std::string &ename, const std::string &qname)
        {
            _binding->unbind(ename, qname);
        }
        // 获取交换机的所有绑定信息
        MsgQueueBindingMap getExchangeBinding(const std::string &ename)
        {
            return _binding->getExchangeBinding(ename);
        }

        // 发布一条消息, DeliveryMode delivery_mode不用传，我们在内部会判断
        bool basePublish(const std::string &qname,basicProperties *bp, const std::string &body)
        {
            // 队列必须得存在
            MsgQueue::ptr mq = _queue->getQueue(qname);
            if (mq.get() == nullptr)
            {
                DLOG("发布消息失败,队列%s不存在\n", qname.c_str());
                return false;
            }
            DeliveryMode mode=mq->durable?DeliveryMode::DURABLE:DeliveryMode::UNDURABLE;
            return _message->insert(qname,bp,body,mq->durable);
        }

        // 获取一条消息
        MessagePtr basicConsume(const std::string &qname)
        {
            //获取指定队列的一条消息
            return _message->front(qname);
        }

        // 确认一条消息
        void ack(const std::string &qname, const std::string &msg_id)
        {
            // DLOG("虚拟机模块,msg_id为：%s",msg_id.c_str());
            _message->ack(qname,msg_id);
        }

        void clear()
        {
            _exchange->clear();
            _queue->clear();
            _binding->clear();
            _message->clear();
        }
        //以下接口，只为测试使用
        bool existsExchange(const std::string& ename)
        {
            return _exchange->isExits(ename);
        }
        bool existsQueue(const std::string& qname)
        {
            return _queue->isExists(qname);
        }
        bool existsBind(const std::string& ename,const std::string& qname)
        {
            return _binding->isExists(ename,qname);
        }
        //获取所有队列
        MsgQueueMap allQueues()
        {
            return _queue->allQueues();
        }
    private:
        std::string _hostname;
        ExchangeManagger::ptr _exchange; // 交换机模块
        MsqQueueManagger::ptr _queue;    // 队列模块
        BindingManager::ptr _binding;    // 绑定关系模块
        MessageManager::ptr _message;    // 消息模块
    };
}
#endif